<?PHP
/**
 * OpenStation
 *
 * @Application : OSException.class.php
 * @Encode : 65001 Unicode ( UTF-8 NO BOM )
 * @Description : OpenStation自定义异常处理类
 * @Author : HK <hkyyang@gmail.com>
 */

class OSException extends Exception {

    private $type;
    private $extra = FALSE;

    /**
     * 构造方法
     *
     * @static
     * @access public
     * @param String : $message, 错误信息
     * @param Integer : $code, 错误代码
     * @param Boolean : $extra, 去除多余的Trace信息
     * @return *
     */
    public function __construct( $message, $code = 0, $extra = FALSE ) {
        // 调用Exception父类构造
        parent :: __construct( $message, $code );
        $this -> type = get_class( $this );
        $this -> extra = $extra ? TRUE : FALSE;
    }

    /**
     * __toString 魔术方法
     *
     * @static
     * @access public
     * @param $
     * @return Array
     */
    public function __toString() {
        // 存储到Cache中安全操作
        Cache :: set( 'TRACE', $this -> getTrace() );
        // 去除多余Trace信息
        if( $this -> extra ) {
            Cache :: shift( 'TRACE' );
        }
        $class = Cache :: get( 'TRACE.0.CLASS' );
        $function = Cache :: get( 'TRACE.0.FUNCTION' );
        $this -> file = Cache :: get( 'TRACE.0.FILE' );
        $this -> line = Cache :: get( 'TRACE.0.LINE' );
        // Trace信息出栈
        Cache :: out( 'TRACE' );
        $time = date( 'y-m-d H:i:m' );
        $error['message'] = $this -> message;
        $error['type'] = $this -> type;
        $error[ 'class' ] = $class;
        $error[ 'function' ] = $function;
        $error[ 'file' ] = $this -> file;
        $error[ 'line' ] = $this -> line;

        // 开启了调试，显示整理更多信息
        if( Cache :: get( '@.ERROR.DEBUG' ) && ! is_null( $this -> file ) && basename( $this -> file ) != basename( Cache :: get( 'SERVER.CACHE_FILE' ) ) ) {
            $code = file( $this -> file );
            $max_line = Cache :: get( 'OPENSTATION.ERROR.DEBUG_DETAIL_MAX_LINE' ) ? Cache :: get( 'OPENSTATION.ERROR.DEBUG_DETAIL_MAX_LINE' ) : 2;
            $error[ 'detail' ] = "\n";
            for( $i = $this -> line - $max_line; $i < $this -> line + $max_line; $i ++ ) {
                // 跳过不存在的行
                if( $i < 0 ) {
                    continue;
                }
                // 当前异常所在行
                if( $this -> line == $i ) {
                    $error[ 'detail' ] .= '<div><span class="line">' . ( $i ) . '</span><span class="error_line">' . $this -> highlight_code( $code[ $i - 1 ] ) . "</span></div>\n";
                // 异常周边行
                } else {
                    $error[ 'detail' ] .= '<div><span class="line">' . ( $i ) . '</span>' . $this -> highlight_code( $code[ $i - 1 ] ) . "</div>\n";
                }
            }
        }
        return $error;
    }

    /**
     * highlight_code 代码高亮
     *
     * @access private
     * @param String : $code
     * @param Boolean : $errline
     * @return String
     */
    private function highlight_code( $code, $errline = FALSE ) {
        $code = '<?PHP' . str_replace( array( ' ', "\t" ), array( '/*__NBSP__*/', '/*__TAB__*/' ), $code ). '?>';
        ob_start();
        ob_implicit_flush( 0 );
        highlight_string( $code );
        $code = ob_get_clean();
        preg_match( '/<\/span>\s*?(.*?)(?=\s*?<span style="color: #0000BB">\?\&gt;)/s', $code, $temp );
        return '<pre>' . str_replace( array( '<br />', "\r", '/*__NBSP__*/', '/*__TAB__*/' ), array( '', '', '&nbsp;', "\t" ), $temp[ 1 ] ) . '</pre>';
    }
}

?>